package ch.zhaw.skuh.turing.model.turingmaschine.rules;

import ch.zhaw.skuh.turing.model.turingmaschine.Addition_N_ary;

public class AdditionRuleSet extends RuleSet {

	public AdditionRuleSet(Addition_N_ary tc) {
		super(tc);
	}

	// add t1 + t2 + t3
	protected String getNewValues(int t1, int t2, int t3) {
		int sum = t1 + t2 + t3;
		// new value in tape 2
		String n = Integer.toString(sum, tc.getRadix());
		n = n.substring(n.length() - 1);
		// overrun to "1" or blank?
		String o = (sum >= tc.getRadix()) ? "1" : "_";
		// t1 is blank, t3 has overrun
		return "_" + n + o;
	}

	protected void addRule_AdditionSubtraction(int q, int exitNormal,
			int exitSpecial, int[] tapes) {
		int e = exitNormal;

		// t3 can only contain "1" or blank !!

		// to tc.getRadix() !! (="_")
		for (int iT1 = 0; iT1 <= tc.getRadix(); iT1++) {
			String t1 = (iT1 == tc.getRadix()) ? "_" : Integer.toString(iT1,
					tc.getRadix());
			for (int iT2 = 0; iT2 <= tc.getRadix(); iT2++) {
				String t2 = (iT2 == tc.getRadix()) ? "_" : Integer.toString(
						iT2, tc.getRadix());

				// t3 can only contain "1" or blank !!
				for (int iT3 = 0; iT3 <= 1; iT3++) {
					String t3 = (iT3 == 0) ? "_" : Integer.toString(iT3,
							tc.getRadix());

					String tNew;
					String tOld = t1 + t2 + t3;
					// fill tNew
					int[] temp = new int[3];
					temp[0] = (iT1 == tc.getRadix()) ? 0 : iT1;
					temp[1] = (iT2 == tc.getRadix()) ? 0 : iT2;
					temp[2] = (iT3 == tc.getRadix()) ? 0 : iT3;
					tNew = getNewValues(temp[0], temp[1], temp[2]);

					// all 3 tapes blank
					if (iT1 == tc.getRadix() && iT2 == tc.getRadix()
							&& iT3 == 0) {
						// all 3 tapes blank --> exit
						tc.addRulePadded(q, tOld, e, "___", "110", tapes);

					} else

					// 2 tapes blank
					// t1, t2 blank
					if (iT1 == tc.getRadix() && iT2 == tc.getRadix()) {
						addRulesPart_Blank1_2(q, e, exitSpecial, tapes, tOld,
								tNew);
					} else

					// t1, t3 blank
					if (iT1 == tc.getRadix() && iT3 == 0) {
						addRulesPart_Blank1_3(q, e, exitSpecial, tapes, tOld,
								tNew);
					} else

					// t2, t3 blank
					if (iT2 == tc.getRadix() && iT3 == 0) {
						addRulesPart_Blank2_3(q, e, exitSpecial, tapes, tOld,
								tNew);
					} else

					// 1 tape blank
					// t1 blank (t2, t3 filled)
					if (iT1 == tc.getRadix()) {
						addRulesPart_Blank1(q, e, exitSpecial, tapes, tOld, tNew);
					} else

					// t2 blank (t1, t3 filled)
					if (iT2 == tc.getRadix()) {
						addRulesPart_Blank2(q, e, exitSpecial, tapes, tOld, tNew);
					}

					// t3 is blank or "1"
					else {
						addRulesPart_NoneBlank(q, e, exitSpecial, tapes, tOld, tNew);
					}
				}
			}
		}
	}

	protected void addRulesPart_Blank1_2(int q, int exitNormal,
			int exitSpecial, int[] tapes, String tOld, String tNew) {
		// *** new first digit from overrun ***
		// write overrun --> exit
		// done, forward tape 2 (the result) and --> exit
		tc.addRulePadded(q, tOld, exitNormal, tNew, "110", tapes);
	}

	protected void addRulesPart_Blank1_3(int q, int exitNormal,
			int exitSpecial, int[] tapes, String tOld, String tNew) {
		// done, forward tape 2 (the result) and --> exit
		tc.addRulePadded(q, tOld, exitNormal, tNew, "110", tapes);
	}

	protected void addRulesPart_Blank2_3(int q, int exitNormal,
			int exitSpecial, int[] tapes, String tOld, String tNew) {
		// t1 is larger then t2 --> continue
		tc.addRulePadded(q, tOld, q, tNew, "-1-10", tapes);
	}

	protected void addRulesPart_Blank1(int q, int exitNormal, int exitSpecial, int[] tapes,
			String tOld, String tNew) {
		int e = exitNormal;
		// check overrun
		if (tNew.substring(2).compareTo("_") == 0) {
			// no new overrun --> exit
			tc.addRulePadded(q, tOld, e, tNew, "110", tapes);
		} else {
			// new overrun --> continue
			tc.addRulePadded(q, tOld, q, tNew, "-1-10", tapes);
		}
	}

	protected void addRulesPart_Blank2(int q, int exitNormal, int exitSpecial, int[] tapes,
			String tOld, String tNew) {
		// --> continue
		tc.addRulePadded(q, tOld, q, tNew, "-1-10", tapes);
	}
	
	// t3 is blank or "1" !!!
	protected void addRulesPart_NoneBlank(int q, int exitNormal, int exitSpecial, int[] tapes,
			String tOld, String tNew) {
		// t1 and t2 filled --> continue
		// --> continue
		tc.addRulePadded(q, tOld, q, tNew, "-1-10", tapes);
	}
	

	@Override
	public int setRules(int minState, int exitNormal, int exitSpecial,
			int[] tapes) {
		return setAdditionRules(minState, exitNormal, exitSpecial, tapes);
	}

	protected int setAdditionRules(int minState, int exitNormal,
			int exitSpecial, int[] tapes) {
		// *** addition rules ***

		// everything in tapes 1, 2 and 3
		int[] tapesCurrent = new int[] { tapes[0], tapes[1], tapes[2] };

		// *** q0 rules ***
		// run backwards, add tape 1+2+3 to t3 and put
		// temporary overrun to tape 3
		addRule_AdditionSubtraction(minState + 0, exitNormal, -1, tapesCurrent);

		// loaded rule-set, return new minState
		return minState + COUNTSTATES;
	}

}
